#include "uccontext.h"
#include <sys/mman.h>

UContext::UContext(size_t stacksize, ProcFunc func,void* args)
{
    m_stat                      = UC_INIT;
    m_func                      = func;
    m_args                      = args;
    m_stacksize                 = stacksize;

    m_stack                     = NULL;
    m_stack                     = mmap(NULL, stacksize, PROT_READ | PROT_WRITE,
                                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    if ( m_stack == NULL )
    {
        throw StackException("create stack failed");
    }

    getcontext(&m_context);
    m_context.uc_stack.ss_sp    = m_stack;
    m_context.uc_stack.ss_size  = m_stacksize;
    m_context.uc_stack.ss_flags = 0;
    m_context.uc_link           = get_init_context();
    makecontext(&m_context, (void (*)(void))UContext::run, 1, this);
}

UContext::~UContext()
{
    if ( m_stack != NULL )
    {
        munmap(m_stack, m_stacksize);
        m_stack = NULL;
    }
}

UContext* create(size_t stacksize, ProcFunc func,void* args)
{
    return new UContext(stacksize,func,args);
}

void UContext::run(UContext* ptrUContext)
{
    if ( ptrUContext == NULL )
        return;

    ptrUContext->m_stat = UC_RUNNING;
    ptrUContext->m_func(ptrUContext->m_args);
    ptrUContext->m_stat = UC_END;
}

bool UContext::resume()
{
    swapcontext(get_init_context(), &m_context);
    return true;
}

bool UContext::yield()
{
    m_stat  = UC_YIELD;
    swapcontext(&m_context, get_init_context());
    return true;
}

ucontext_t* UContext::get_init_context()
{
    static __thread ucontext_t init_context;
    return &init_context;
}



